/*
 * Copyright (C) 2000-2004 Technical University of Ilmenau, Germany
 *                         Department of Electronic Circuits & Systems
 *
 * You may only use this file according to the terms of the license agreement included
 * within the file LICENSE which is distributed together with the software package.
 *
 * CVS Info:
 * $Author: rummler $
 * $Date: 2004/03/10 20:19:51 $
 * $Revision: 1.1.2.1 $
 * $State: Exp $
 * $RCSfile: TrivialAlgorithm.java,v $
 *
 */
package elka.isi;

import elka.isi.comparator.HarvestingComparator;
import elka.isi.comparator.HuntingComparator;
import elka.isi.gene.RabbitGenotypeBuilder;
import elka.isi.gene.RoeGenotypeBuilder;
import elka.isi.gene.WolfGenotypeBuilder;
import elka.isi.individual.*;
import elka.isi.operator.*;
import elka.isi.operator.writer.PopulationsQuantityWriter;
import elka.isi.operator.writer.QuantityAndScoresWriter;
import elka.isi.util.RWUtils;
import org.evolvica.core.common.Collector;
import org.evolvica.core.eval.DefaultFloatScoreComparator;
import org.evolvica.core.eval.ReverseFloatScoreComparator;
import org.evolvica.core.population.ElitistInsertion;
import org.evolvica.core.terminate.ConditionalRouter;
import org.evolvica.core.terminate.CounterCondition;
import org.evolvica.engine.AbstractAlgorithm;
import org.evolvica.util.RandomUtils;

/** Trivial Algorithm.
 *
 * @author Andreas Rummler
 * @since 0.4.0
 * @version $Revision: 1.1.2.1 $ $Date: 2004/03/10 20:19:51 $
 */
public class RWAlgorithm extends AbstractAlgorithm {
	
	// a comparator which compares individuals by their (integer) scores
	// and assumes that a higher score is a better score: we need this comparator later!
	//	protected DefaultIntegerScoreComparator comparator = new DefaultIntegerScoreComparator();
	// try out what happens, if you change the comparator to this one:
//  dostepna liczba marchewki 
	private static final int CARROT_AMOUNT = 200000;	
//	poczatkowa liczba krolikow
	private static final int RABBITS_COUNT = 200;
	
//	poczatkowa liczba saren
	private static final int ROES_COUNT = 100;

//  apetyt teraz bedzie zalezal od konkretnego osobnika / Jacek    
//  apetyt krolika na marchewke	
//	private static final int RABBITS_APETITE = 1;
//  apetyt sarny na marchewke
//    private static final int ROE_APETITE = 4;

//	liczba iteracji
	public static final int ITERATIONS_NUMBER = 1000;
//	poczatkowa liczba wilkow
	private static final int WOLFS_COUNT = 10;
//	apetyt wilkow - ile jednostek jedzenia musi zjesc
	private static final int WOLF_APETITE = 20; 
//	max wartosc parametru (genu)
	public static final int MAX_PARAMETER = 100;
//	min wartosc parametru
	public static final int MIN_PARAMETER = 1;
//	maksymalny zakres mutacji
	public static final int MUTATION_RANGE = 40;
	//protected DefaultFloatScoreComparator comparator = new DefaultFloatScoreComparator();
	protected HuntingComparator comparator = new HuntingComparator();
    protected HarvestingComparator harvestingComparator = new HarvestingComparator();
	
	QuantityAndScoresWriter initialStateWriter = new QuantityAndScoresWriter("initial_scores.csv", "initial_pops.csv", "initial_genetic.csv");
	PopulationsQuantityWriter afterHarvestingStateWriter = new PopulationsQuantityWriter("afterHarvesting.csv");
	PopulationsQuantityWriter afterHuntingStateWriter = new PopulationsQuantityWriter("afterHunting.csv");
	
	protected String sinkID;
	
	// in the setup method everything is done to create an algorithm
	public void setup() throws Exception {
		
		// setting up statistics
		// order in this array => order of collumns in output
		int[] arrayToStats = {RWUtils.COUNTER_COLUMN, RWUtils.RABBITS_SIZE_COLUMN, RWUtils.WOLVES_SIZE_COLUMN, RWUtils.ROES_SIZE_COLUMN, RWUtils.RABBITS_FIGHT_AVERAGE_COLUMN, RWUtils.WOLVES_FIGHT_AVERAGE_COLUMN};
		// and were to store stats
		RWUtils.outputFileLocation = "output\\stats.csv";
		RWUtils.statsToPrint = arrayToStats;
		
				
		// first step: create instances of operators that are to be used
		RWInitializer init = new RWInitializer(); // a problem dependent initializer
		
		// ustawienia operatora harvestingu
		HarvestingEcosystem harvesting = new HarvestingEcosystem();
		harvesting.setComparator(harvestingComparator);
//		harvesting.setRabbitAppetite(RABBITS_APETITE);
//        harvesting.setRoeAppetite(ROE_APETITE);
        harvesting.setCarrotAvailable(CARROT_AMOUNT);
        harvesting.setFilter( new ElitistInsertion( (float) 0, (float) 0, comparator ) );
        
		HuntingEcosystem hunting = new HuntingEcosystem(); // a population, that sorts its contents
//		Duplicator duplicator = new Duplicator();
		AnimalMultipointCrossover replicator = new AnimalMultipointCrossover();
		ConditionalRouter router = new ConditionalRouter();
		
		Collector collector = new Collector();
		RWEvaluator eval = new RWEvaluator(); // our own evaluator
		RWMutator mutator = new RWMutator();
//		TrivialSink sink = new TrivialSink(); // and a sink that captures the results of the algorithm
		RWSink sink = new RWSink();
		sink.setComparator( comparator );
		// the initializer should create 10 individuals; the next line sets
		// the appropriate property
//		init.setSetSize( 10 );
		init.setWolfSetSize(WOLFS_COUNT);
		init.setRabbitSetSize(RABBITS_COUNT);
		init.setRoeSetSize(ROES_COUNT);
		// we need to tell the population how to sort the individuals
		// therefore we append our comparator
		hunting.setWolfApetite(WOLF_APETITE);
		hunting.setComparator( comparator );
		// we use elitist reinsertion for replacing individuals in our population
		hunting.setFilter( new ElitistInsertion( (float) 1, (float) 1, comparator ) );
		
		replicator.setIndividualBuilder(RabbitIndividual.class, new RabbitBuilder());
		replicator.setIndividualBuilder(WolfIndividual.class, new WolfBuilder());
        replicator.setIndividualBuilder(RoeIndividual.class, new RoeBuilder());

        replicator.setGeneBuilder(RabbitIndividual.class, new RabbitGenotypeBuilder());
		replicator.setGeneBuilder(WolfIndividual.class, new WolfGenotypeBuilder());
		replicator.setGeneBuilder(RoeIndividual.class, new RoeGenotypeBuilder());


        // we need a condition for our router: 1000 generations
		router.setCondition( new CounterCondition( ITERATIONS_NUMBER ) );
		// now we need to connect all operators together
		// connect the output of the initializer to the first input of the collector
		connect( init, collector, 0 );
		// connect the collector to the evaluator
		connect( collector, eval );
		// evaluator to population
//		od n = 0
		connect( eval, initialStateWriter ); 	//(3n + 1) linia tuz po ewaluacji
		connect(initialStateWriter, harvesting); 
		connect( harvesting, afterHarvestingStateWriter); // (3n + 2) linia tuz po harvestingu
		connect(afterHarvestingStateWriter, hunting);
		connect( hunting, afterHuntingStateWriter); // (3n + 3) linia po huntingu
//		connect(eval,harvesting);
//		connect(harvesting,hunting);
//		connect(hunting,router);
		
		// population to the router
		connect( afterHuntingStateWriter, router );
		// connect the 0-output of the evaluator to the input of the duplicator
		// the individuals will take this path if the condition in the router is false
		connect( router, 0, replicator );
		// connect the 1-output of the evaluator to the input of the sink
		// the individuals will take this path if the condition in the router is true
		connect( router, 1, sink );
		// connect the duplicator to the mutator
		connect( replicator, mutator );
		// and from the mutator back to the collector: this closes the loop!
		connect( mutator, collector, 1 );
		// THAT'S ALL !!!
		// remember the sink ID for later use
		this.sinkID = sink.getId();
		
		
	}
	
	// in the teardown method we can extract the results of our algorithm
	public void teardown() {
		afterHuntingStateWriter.close();
		initialStateWriter.close();
		afterHarvestingStateWriter.close();
		/*
		// get our sink
		TrivialSink sink = (TrivialSink) getElementById( sinkID ).getOperator();
		// get the individuals from the sink
		IIndividual[] contents = sink.consumedIndividuals();
		// now search for the best individual
		IIndividual best = contents[0];
		for ( int i = 0; i < contents.length; i++ ) {
			if ( comparator.compare( best, contents[i] ) < 0 ) {
				best = contents[i];
			}
		}
		// print the result:
		EVLog.def.info( "Finished! The best individual had a score of " + best.getScore() );
		*/
	}
	
	// now create a main method to be able to run the algorithm
	public static void main( String[] args ) throws Exception {
		new RWAlgorithm().execute();
		//new AlgorithmWriter().write( algorithm );
		//IAlgorithm algorithm = new AlgorithmBuilder().build( "file:/c:/tmp/algorithm.xml" );
		//algorithm.execute();
		//System.out.println( algorithm.getClass().getName() );
		//SphereAlgorithm algorithm = new SphereAlgorithm();
		//new AlgorithmWriter().write( algorithm );
		//algorithm.execute();
	}
	
}
